﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Forms;
using EmbeddedSharp.Core;
using Zove.Scripting.Editor;

namespace EmbeddedSharp.Scripting.SpecManager {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();

            this.Load += new EventHandler(Form1_Load);
        }

        public void Form1_Load(object sender, EventArgs e) {

        }

        private void cmdRun_Click(object sender, EventArgs e) {
            RunSelected();
        }

        /// <summary>
        /// Run the source
        /// </summary>
        /// <param name="source">the source</param>
        /// <returns>result</returns>
        public string Run(string source) {
            ConsoleStreamWriter writer = new ConsoleStreamWriter();
            Console.SetOut(writer);

            ScriptingObject scriptObject = new ScriptingObject(source);
            scriptObject.Context.GetFunctionManager().FunctionLoader.LoadFromFile(this.fileName);

            scriptObject.Run();

            return writer.Stream.ToString().Trim();
        }

        /// <summary>
        /// Run the example in the selected row
        /// </summary>
        public void RunSelected() {
            string result = Run(Source);

            DataGridViewCell cellResult = GetCell("ColResult");
            cellResult.Value = result;
        }

        /// <summary>
        /// Get the requested cell
        /// </summary>
        /// <param name="name">the name of the cell</param>
        /// <returns>the requested cell</returns>
        public DataGridViewCell GetCell(string name) {
            if (this.gvFunctions.SelectedCells.Count > 0) {
                DataGridViewRow row = this.gvFunctions.Rows[
                    this.gvFunctions.SelectedCells[0].RowIndex];
                return row.Cells[name];
            }

            throw new NullReferenceException("Cell is not existed.");
        }

        public string Source {
            set {
                DataGridViewCell cell = GetCell("ColSample");
                cell.Value = value;
            }
            get {
                DataGridViewCell cell = GetCell("ColSample");
                if (cell.Value == null) {
                    return string.Empty;
                }

                return cell.Value.ToString();
            }
        }

        public void VerifySelected() {
            ScriptingObject script = new ScriptingObject(Source);
            script.Context.GetFunctionManager().FunctionLoader.LoadFromFile(this.fileName);
            script.Run();

            DataGridViewCell cellOutput = GetCell("ColExpectedResult");
            string expr = cellOutput.Value.ToString();

            object ret = script.Context.Evaluate(expr);
            if (ret == null) {
                cellOutput.Value = "<ERR: assert result is null>";
                return;
            }

            bool result = false;
            bool done = Boolean.TryParse(ret.ToString(), out result);

            DataGridViewCell cellActualResult = GetCell("ColResult");
            if (done) {
                    cellActualResult.Value = result.ToString();
            } else {
                cellActualResult.Value = ret;
            }
        }

        private void cmdStop_Click(object sender, EventArgs e) {
            StopSelected();
        }

        public void StopSelected() {
        }

        private void cmdAssertAll_Click(object sender, EventArgs e) {
            AssertAll();
        }

        public void AssertAll() {
            foreach (DataGridViewRow row in this.gvFunctions.Rows) {
                row.Selected = true;
                VerifySelected();
            }
        }

        private void cmdAssert_Click(object sender, EventArgs e) {
            VerifySelected();
        }

        private void editExampleToolStripMenuItem_Click(object sender, EventArgs e) {
            ScriptingEditorView view = new ScriptingEditorView(Source);

            view.Show();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e) {
            this.Close();
        }

        private void btnEditSource_Click(object sender, EventArgs e) {
        }

        private string fileName;

        private void cmdOpen_Click(object sender, EventArgs e) {
            OpenFileDialog view = new OpenFileDialog();

            view.Filter = "All Function Libraries |*.dll";
            if (view.ShowDialog() == DialogResult.OK) {
                this.fileName = view.FileName;

                DefaultDependencyManager.Instance.FunctionManager.FunctionLoader.LoadFromFile(view.FileName);
                List<FuncNode> list = LoadLibrary(view.FileName);
                List<FunctionAttribute> fl = GetAttributes(list);

                this.gvFunctions.DataSource = fl;
                this.statusStrip1.Text = string.Format(
                    "Documented/Total: {0}/{1}", fl.Count, list.Count);
            }
        }

        /// <summary>
        /// Load all the functions
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public List<FuncNode> LoadLibrary(string fileName) {
            List<FuncNode> list = new List<FuncNode>();

            try {
                Assembly assembly = Assembly.LoadFrom(fileName);
                Type[] types = assembly.GetTypes();

                foreach (Type type in types) {
                    FuncNode instance = null;

                    try {
                        object obj = assembly.CreateInstance(type.FullName);
                        if (obj is FuncNode) {
                            instance = obj as FuncNode;
                            list.Add(instance);
                        }
                    } catch (Exception ex) {
                    }
                }
            } catch (Exception ex) {
                throw ex;
            }

            return list;
        }

        public List<FunctionAttribute> GetAttributes(List<FuncNode> fl) {
            List<FunctionAttribute> list = new List<FunctionAttribute>();

            foreach (FuncNode fn in fl) {
                FunctionAttribute fa = DefaultFunctionManager.GetAttributeByNode(fn);
                if (fa == null) {
                    continue;
                }

                list.Add(fa);
            }

            return list;
        }

        public virtual FuncNode LoadFunction(Assembly assembly, string p) {
            return assembly.CreateInstance(p) as FuncNode;
        }
    }
}
